import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:im_app/im/page/view/component/UserIconView.dart';
import 'package:im_app/im/service/ImMessageSendService.dart';
import 'package:im_app/im/uploadAndDownload/FileUploadService.dart';
import 'package:im_app/im/util/CollectionUtil.dart';
import 'package:im_app/im/util/HexColor.dart';
import 'package:im_app/im/util/ImSingleton.dart';
import 'package:im_app/im/util/UiUtil.dart';
import 'package:logger/logger.dart';

import '../../../../pojo/ImPojo.dart';
import '../../../../uploadAndDownload/FileDownloadService.dart';
import '../../../../uploadAndDownload/UploadAndDownloadDto.dart';
import '../../../../util/ImConstant.dart';
import '../../../../util/LoggerUtil.dart';
import '../../../bloc/MessageListCubit.dart';
import '../../../sub/MessageRefInfoPage.dart';
import '../../../sub/UserInfoPage.dart';
import '../pane/MessagePane.dart';

class MessageItemView extends StatelessWidget {
  final WrapImMessage wrapMessage;
  final _logger = Logger();

  MessageItemView({required this.wrapMessage, super.key});

  @override
  Widget build(BuildContext context) {
    var messageListCubit = context.read<MessageListCubit>();
    Widget messagePane = wrapMessage.message.currentUserId == wrapMessage.message.fromUserId
        ? _buildRightMessagePane(context)
        : _buildLeftMessagePane(context);

    Widget? selectedPane = messagePane;
    if (messageListCubit.state.selectable) {
      selectedPane = InkWell(
        onTap: () {
          if (CollectionUtil.contain(messageListCubit.state.selectedMessages, (wm)=>wm.message.id == wrapMessage.message.id)) {
            messageListCubit.add(MessageListSelectMessageEvent(wrapMessage, false));
          } else {
            messageListCubit.add(MessageListSelectMessageEvent(wrapMessage, true));
          }
        },
        child: messagePane,
      );
    }
    return Container(
        color: wrapMessage.isSelected && messageListCubit.state.selectable ? Colors.grey.shade300 : Colors.transparent,
        padding: const EdgeInsets.only(top: 5, bottom: 5),
        child: selectedPane
    );
  }

  Widget _buildRightMessagePane(BuildContext context) {
    return Row(
      mainAxisSize: MainAxisSize.min,
      crossAxisAlignment: CrossAxisAlignment.start,
      mainAxisAlignment: MainAxisAlignment.end,
      children: [
        _buildMessageRadio(context),
        const Expanded(child: Text('')),
        _buildRightContent(context),
        if (wrapMessage.message.messageType != ImMessageType.Image) _buildRightPath(),
        _buildMessageTitle(context),
      ],
    );
  }

  Widget _buildLeftMessagePane(BuildContext context) {
    return Row(
      mainAxisSize: MainAxisSize.min,
      crossAxisAlignment: CrossAxisAlignment.start,
      mainAxisAlignment: MainAxisAlignment.start,
      children: [
        const SizedBox(width: 10,),
        _buildMessageRadio(context),
        _buildMessageTitle(context),
        if (wrapMessage.message.messageType != ImMessageType.Image) _buildLeftPath(),
        _buildLeftContent(context),
        const Expanded(child: Text('')),
      ],
    );
  }

  Widget _buildMessageTitle(BuildContext context) {
    return GestureDetector(
      child: ClipRRect(
        borderRadius: const BorderRadius.all(Radius.circular(30)),
        child: UserIconView(user: wrapMessage.message.fromImUser!, iconSize: ImConstant.IM_USER_ICON_SIZE - 15,),
      ),
      onTap: () {
        Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) {
          return UserInfoPage(user: wrapMessage.message.fromImUser!);
        }));
      },
    );
  }

  Widget _buildLeftContent(BuildContext context) {
    String? groupCode = wrapMessage.message.groupCode;
    if (groupCode != null) {
      return Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Padding(
            padding: const EdgeInsets.only(bottom: 5),
            child: Text(
              wrapMessage.message.fromGroupUser?.userName ?? (wrapMessage.message.fromImUser?.userName ??''),
              style: const TextStyle(fontSize: ImConstant.IM_SMALL_SIZE),
            ),
          ),
          _buildLeftContentItem(context),
          if (wrapMessage.message.refMessages != null)
            Padding(
              padding: const EdgeInsets.only(top: 5),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: wrapMessage.message.refMessages!.map((refMessage) => _buildRefLeftPane(context, refMessage))
                    .toList(),
              ),
            ),
        ],
      );
    } else {
      if (wrapMessage.message.refMessages != null) {
        var result = <Widget>[];
        result.add(_buildLeftContentItem(context));
        var refPanes = wrapMessage.message.refMessages!.map((refMessage) => _buildRefLeftPane(context, refMessage)).toList();
        result.addAll(refPanes);
        return Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: result,
        );
      } else {
        return _buildLeftContentItem(context);
      }
    }
  }

  Widget _buildRightContent(BuildContext context) {
    String? groupCode = wrapMessage.message.groupCode;
    if (groupCode != null) {
      return Column(
        crossAxisAlignment: CrossAxisAlignment.end,
        children: <Widget>[
          Padding(
            padding: const EdgeInsets.only(bottom: 5),
            child: Text(
              wrapMessage.message.fromGroupUser?.userName ?? '',
              style: const TextStyle(fontSize: ImConstant.IM_SMALL_SIZE),
            ),
          ),
          _buildRightContentItem(context),
          if (wrapMessage.message.refMessages != null)
            Padding(
              padding: const EdgeInsets.only(top: 5),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.end,
                children: wrapMessage.message.refMessages!.map((refMessage) => _buildRefRightPane(context, refMessage)).toList(),
              ),
            ),
        ],
      );
    } else {
      if (wrapMessage.message.refMessages != null) {
        var result = <Widget>[];
        result.add(_buildRightContentItem(context));
        var refPanes = wrapMessage.message.refMessages!.map((refMessage) => _buildRefRightPane(context, refMessage)).toList();
        result.addAll(refPanes);
        return Column(
          crossAxisAlignment: CrossAxisAlignment.end,
          children: result,
        );
      } else {
        return _buildRightContentItem(context);
      }
    }
  }

  Widget _buildLeftContentItem(BuildContext context) {
    return Row(
      crossAxisAlignment: CrossAxisAlignment.end,
      children: [
        ConstrainedBox(
            constraints: const BoxConstraints(maxWidth: ImConstant.MESSAGE_MAX_WIDTH),
            // child: MessagePaneEnum.getByMessageType(wrapMessage.message.messageType).executor(wrapMessage.message),
            child: MessagePane(
              wrapMessage: wrapMessage,
            )
        ),
        _buildMessageStatus(context),
      ],
    );
  }

  Widget _buildRightContentItem(BuildContext context) {
    return Row(
      crossAxisAlignment: CrossAxisAlignment.end,
      children: [
        _buildMessageStatus(context),
        ConstrainedBox(
            constraints: const BoxConstraints(maxWidth: ImConstant.MESSAGE_MAX_WIDTH),
            // child: MessagePaneEnum.getByMessageType(wrapMessage.message.messageType).executor(wrapMessage.message),
            child: MessagePane(
              wrapMessage: wrapMessage,
            )
        )
      ],
    );
  }

  Widget _buildMessageStatus(BuildContext context) {
    if (wrapMessage.status == WrapImMessageStatus.uploading) {
      return Padding(
        padding: const EdgeInsets.only(left: 5, right: 5),
        child: SizedBox(height: 15, width: 15, child: CircularProgressIndicator(value: wrapMessage.uploadProgress),),
      );
    }
    if (wrapMessage.status == WrapImMessageStatus.downloading) {
      return Padding(
        padding: const EdgeInsets.only(left: 5, right: 5),
        child: SizedBox(height: 15, width: 15, child: CircularProgressIndicator(value: wrapMessage.downloadProgress),),
      );
    }
    if (wrapMessage.statusFile == '') {
      return const Text('');
    }
    return Padding(
      padding: const EdgeInsets.only(left: 5, right: 5, top: 20),
      child: GestureDetector(
        child: Image(
          image: AssetImage(wrapMessage.statusFile),
          height: 12,
          width: 12,
        ),
        onTap: () {
          _handleNoSuccessMessage(context, wrapMessage.status);
        },
      ),
    );
  }

  Widget _buildLeftPath() {
    String? groupCode = wrapMessage.message.groupCode;
    return Padding(
      padding: EdgeInsets.only(left: 2, top: groupCode != null ? 27 : 6),
      child: CustomPaint(
        painter: LeftPath(),
        size: const Size(5, 10),
      ),
    );
  }

  Widget _buildRightPath() {
    String? groupCode = wrapMessage.message.groupCode;
    return Padding(
      padding: EdgeInsets.only(right: 2, top: groupCode != null ? 27 : 6),
      child: CustomPaint(
        painter: RightPath(),
        size: const Size(5, 10),
      ),
    );
  }

  Widget _buildMessageRadio(BuildContext context) {
    var messageListCubit = context.read<MessageListCubit>();
    return Visibility(
      visible: messageListCubit.state.selectable,
        child: Radio(
            value: wrapMessage.message.id??-1,
            groupValue: wrapMessage.isSelected ? wrapMessage.message.id! : 0,
            onChanged: (value) {
              _logger.i('selected $value', time: DateTime.now());
              // if (CollectionUtil.contain(messageListCubit.state.selectedMessages, (wm)=>wm.message.id == wrapMessage.message.id)) {
              //   messageListCubit.add(MessageListSelectMessageEvent(wrapMessage, false));
              // } else {
              //   messageListCubit.add(MessageListSelectMessageEvent(wrapMessage, true));
              // }
            }
            ),
    );
  }

  Widget _buildRefLeftPane(BuildContext context, ImMessage refMessage) {
    return GestureDetector(
      onTap: () {
        Navigator.of(context).push(MaterialPageRoute(builder: (context){
          return MessageRefInfoPage(message: refMessage);
        }));
      },
      child: Container(
          alignment: Alignment.topLeft,
          padding: const EdgeInsets.only(top: 6, right: 5, bottom: 6, left: 6),
          margin: const EdgeInsets.only(top: 5),
          decoration: ShapeDecoration(
            color: Colors.grey.shade300,
            shape:
            const RoundedRectangleBorder(side: BorderSide.none, borderRadius: BorderRadius.all(Radius.circular(5))),
          ),
          child: ConstrainedBox(
              constraints: const BoxConstraints(maxWidth: 250),
              child: MessageRefPane(
                message: refMessage,
                param: MessageRefParam(maxLines: 1, hasPrefix: true),
              ))
      ),
    );
  }

  Widget _buildRefRightPane(BuildContext context, ImMessage refMessage) {
    return GestureDetector(
      onTap: () {
        Navigator.of(context).push(MaterialPageRoute(builder: (context){
          return MessageRefInfoPage(message: refMessage);
        }));
      },
      child: Container(
          alignment: Alignment.topRight,
          padding: const EdgeInsets.only(top: 6, right: 5, bottom: 6, left: 6),
          margin: const EdgeInsets.only(top: 5),
          decoration: ShapeDecoration(
            color: Colors.grey.shade300,
            shape: const RoundedRectangleBorder(side: BorderSide.none, borderRadius: BorderRadius.all(Radius.circular(5))),
          ),
          child: ConstrainedBox(
              constraints: const BoxConstraints(maxWidth: ImConstant.MESSAGE_MAX_WIDTH),
              // child: MessagePaneEnum.getByMessageType(wrapMessage.message.messageType).executor(wrapMessage.message),
              child: MessageRefPane(
                message: refMessage,
                param: MessageRefParam(maxLines: 1, hasPrefix: true),
              ))
      ),
    );
  }

  void _handleNoSuccessMessage(BuildContext context, WrapImMessageStatus status) async {
    if (status == WrapImMessageStatus.no_send) { // 未发送，进行再次发送
      String userId = ImSingleton.getInstance().session.userId!;
      wrapMessage.message.status = ImMessageStatus.sending;

      ImMessageSendService messageSendService = ImMessageSendService();
      await messageSendService.sendMessages(userId, [wrapMessage.message]).catchError((e) {
        wrapMessage.message.status = ImMessageStatus.failure;
        UiUtil.uiUpdateMessage(wrapMessage.message);
        UiUtil.showSnackBar(context, '消息发送失败');
      });
    }
    var message = wrapMessage.message;
    if (message.currentUserId == message.fromUserId) { // 发送者
      if (wrapMessage.message.messageType.isFile() && (wrapMessage.message.fileStatus == null ||
          wrapMessage.message.fileStatus == ImMessageFileStatus.none ||
          wrapMessage.message.fileStatus == ImMessageFileStatus.created)) {
        if (wrapMessage.message.messageExt?.remote??false) {
          var ip = ImSingleton.getInstance().session.getData("im_ip") as String;
          await FileDownloadService.downFile(message,
                  (FileDownloadResult downResult)=> _downloadCallback(context, message, downResult), ip);
        } else {
          FileUploadService fileUploadService = FileUploadService();
          await fileUploadService.sendFile(wrapMessage.message,
                  (FileUploadResult uploadResult)=> _uploadCallback(context, message, uploadResult));
        }
      }
    } else { // 接受者
      if (!message.messageType.isFile()) {
        return;
      }
      if ((message.fileStatus == ImMessageFileStatus.none)) {
        var ip = ImSingleton.getInstance().session.getData("im_ip") as String;
        await FileDownloadService.downFile(message,
                (FileDownloadResult downResult)=> _downloadCallback(context, message, downResult), ip);
      } else {
        if (context.mounted) {
          UiUtil.showSnackBar(context, '文件在上传中，不能下载');
        }
      }
    }
  }

  _uploadCallback(BuildContext context, ImMessage message, FileUploadResult uploadResult) async {
    _logger.i('[Upload file callback], ${uploadResult.fileUploadSize}/${uploadResult.fileSize}');
    if (uploadResult.errorMsg != null && uploadResult.errorMsg != '') {
      UiUtil.showSnackBar(context, uploadResult.errorMsg);
      return;
    }
    if (uploadResult.isSuccess) {
      UiUtil.showSnackBar(context, '文件上传成功！');
    }
    if (uploadResult.fileSize > 0) {
      double progress = uploadResult.fileUploadSize / uploadResult.fileSize;
      UiUtil.uiUpdateFileUploadProgress(message, progress);
    }
  }

  _downloadCallback(BuildContext context, ImMessage message, FileDownloadResult downResult) {
    _logger.i('[Download file callback], ${downResult.fileDownloadSize}/${downResult.fileSize}', time: DateTime.now());
    if (downResult.errorMsg != null && downResult.errorMsg != '') {
      UiUtil.showSnackBar(context, downResult.errorMsg);
      return;
    }
    if (downResult.isSuccess) {
      UiUtil.showSnackBar(context, '文件下载成功！');
    }
    if (downResult.fileSize > 0) {
      double progress = downResult.fileDownloadSize / downResult.fileSize;
      UiUtil.uiUpdateFileUploadProgress(message, progress);
    }
  }
}

class LeftPath extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    Paint paint = Paint()
      ..color = Colors.white
      ..style = PaintingStyle.fill
      ..strokeWidth = 1;

    Path path = Path();
    path
      ..moveTo(0, 5)
      ..lineTo(5, 0)
      ..lineTo(5, 10)
      ..close();
    canvas.drawPath(path, paint);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) => true;
}

class RightPath extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    Paint paint = Paint()
      ..color = HexColor.fromHex("#95EC69")
      ..style = PaintingStyle.fill
      ..strokeWidth = 1;

    Path path = Path();
    path
      ..moveTo(0, 0)
      ..lineTo(5, 5)
      ..lineTo(0, 10)
      ..close();
    // path.transform(Matrix4.translationValues(5, 2, 0))
    canvas.drawPath(path, paint);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) => true;
}
